package me.zhengjie.inter.rest;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.annotation.Log;
import me.zhengjie.annotation.rest.AnonymousGetMapping;
import me.zhengjie.annotation.rest.AnonymousPostMapping;
import me.zhengjie.aop.annotation.BisLog;
import me.zhengjie.business.domain.Zhsq;
import me.zhengjie.business.service.dto.ZhsqQueryCriteria;
import me.zhengjie.inter.service.MpZhsqService;
import me.zhengjie.modules.security.config.bean.LoginProperties;
import me.zhengjie.modules.security.config.bean.SecurityProperties;
import me.zhengjie.modules.security.security.TokenProvider;
import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.modules.security.service.dto.JwtUserDto;
import me.zhengjie.modules.system.domain.Dept;
import me.zhengjie.modules.system.domain.Role;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.modules.system.service.dto.UserDto;
import me.zhengjie.utils.*;
import me.zhengjie.weixin.WeiXinConfig;
import org.apache.hc.core5.http.ParseException;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author xiahongbo
 * @date 2022-07-10
 **/
@Slf4j
@RestController
@RequiredArgsConstructor
@Api(tags = "微信回调")
@RequestMapping("/weixin")
public class MpWeiXinController {

    private final UserDetailsService userDetailsService;
    private final UserService userService;
    private final SecurityProperties properties;
    private final OnlineUserService onlineUserService;
    private final TokenProvider tokenProvider;
    private final PasswordEncoder passwordEncoder;
    @Resource
    private LoginProperties loginProperties;

    @AnonymousGetMapping("/webPageAuth")
    @ApiOperation("微信网页授权回调")
    public ResponseEntity<Object> webPageAuth(String code, String state, HttpServletRequest request) {
        String url = WeiXinConfig.apiUrl+"/sns/oauth2/access_token?appid="+WeiXinConfig.appId+"&secret="+WeiXinConfig.secretKey+"&code="+code+"&grant_type=authorization_code";
        String res = HttpUtil.get(url);
        // 返回格式
//        {
//            "access_token":"ACCESS_TOKEN",
//                "expires_in":7200,
//                "refresh_token":"REFRESH_TOKEN",
//                "openid":"OPENID",
//                "scope":"SCOPE"
//        }
        // 错误格式
//        {"errcode":40029,"errmsg":"invalid code"}

        log.error(res);
        JSONObject accessToken= JSONObject.parseObject(res);
        String openid = accessToken.getString("openid");
        // 生成令牌与第三方系统获取令牌方式
        User user = userService.findByWxOpenId(openid);
        if(user == null){
            // 没有对应账号则请求更多信息
            String access_token = accessToken.getString("access_token");
            String urlInfo = WeiXinConfig.apiUrl+"/sns/userinfo?access_token="+access_token+"&openid="+openid+"&lang=zh_CN";
            String resUrlInfo = HttpUtil.get(urlInfo);

            log.error(resUrlInfo);
            // 返回格式
//        {
//            "openid": "OPENID",
//                "nickname": NICKNAME,
//                "sex": 1,
//                "province":"PROVINCE",
//                "city":"CITY",
//                "country":"COUNTRY",
//                "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
//                "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
//            "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
//        }
            // 错误格式
//        {"errcode":40003,"errmsg":" invalid openid "}
            JSONObject resUrlInfoJson= JSONObject.parseObject(resUrlInfo);

            user = new User();
            user.setWxOpenId(openid);
            user.setNickName(resUrlInfoJson.getString("nickname"));
            user.setWxAvatarUrl(resUrlInfoJson.getString("headimgurl"));
            String sexNum = resUrlInfoJson.getString("sex");
            if(sexNum.equals("0")){
                user.setGender("未知");
            }else if(sexNum.equals("1")){
                user.setGender("男");
            }else if(sexNum.equals("2")){
                user.setGender("女");
            }

            user.setUsername(openid);
            user.setPassword(passwordEncoder.encode("123456"));
            user.setPhone("13000000000");
            user.setEnabled(true);
            user.setIsAdmin(false);

            // 新增用户，模拟部门
            Dept dept = new Dept();
            dept.setId(DefaultUtil.DEPT_SM);
            user.setDept(dept);

            // 新增用户，模拟角色
            Set<Role> setRole = new HashSet<Role>();
            Role role = new Role();
            role.setId(DefaultUtil.ROLE_SM);
            setRole.add(role);
            user.setRoles(setRole);

            userService.createByUser(user);
        }

        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
        log.error(userDetails.toString());
        log.info("userDetails: {} ", userDetails);
        Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        log.error(authentication.toString());
        log.info("userDetails: {} ", authentication);
        SecurityContextHolder.getContext().setAuthentication(authentication);


        String token = tokenProvider.createToken(authentication);
        log.error(token);
        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
        Map<String, Object> userMap = new HashMap<String, Object>(2) {{
            put("token", properties.getTokenStartWith() + token);
            put("userinfo", jwtUserDto);
        }};
        // 保存在线信息
        onlineUserService.save(jwtUserDto, token, request);
        // 返回 token 与 用户信息
        Map<String, Object> result = PageUtil.toMpContent(userMap);
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(user.getUsername(), token);
        }

        return new ResponseEntity<>(result, HttpStatus.OK);
    }

    @AnonymousGetMapping("/mpPageAuth")
    @ApiOperation("微信小程序登录")
    public ResponseEntity<Object> mpPageAuth(String code, String iv, String phoneCode, String encryptedData, HttpServletRequest request) {
//        https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

//        String jscode2sessionUrl = "http://10.199.17.70:65443/sns/jscode2session?appid=wxfbcfc5894c14db5d&secret=a301f714391543860b107fe8697d8915&js_code="+code+"&grant_type=authorization_code";
        String jscode2sessionUrl = WeiXinConfig.apiUrl+"/sns/jscode2session?appid=wxfbcfc5894c14db5d&secret=a301f714391543860b107fe8697d8915&js_code="+code+"&grant_type=authorization_code";
        String jscode2sessionRes = HttpUtil.get(jscode2sessionUrl);
//        返回的 JSON 数据包
//        属性	类型	说明
//        openid	string	用户唯一标识
//        session_key	string	会话密钥
//        unionid	string	用户在开放平台的唯一标识符，若当前小程序已绑定到微信开放平台帐号下会返回，详见 UnionID 机制说明。
//        errcode	number	错误码
//        errmsg	string	错误信息
//        errcode 的合法值
//        值	说明	最低版本
//        -1	系统繁忙，此时请开发者稍候再试
//        0	请求成功
//        40029	code 无效
//        45011	频率限制，每个用户每分钟100次
//        40226	高风险等级用户，小程序登录拦截 。风险等级详见用户安全解方案

        log.error(jscode2sessionRes);
        JSONObject jscode2sessionJson= JSONObject.parseObject(jscode2sessionRes);
        if(jscode2sessionJson.containsKey("errcode") && jscode2sessionJson.getInteger("errcode") != 0){

            Map<String, Object> userMap = new HashMap<String, Object>(2) {{
                put("code", "-1");
                put("msg", "微信授权错误");
            }};
            // 返回 token 与 用户信息
            Map<String, Object> result = PageUtil.toMpContent(userMap);
            return new ResponseEntity<>(result, HttpStatus.OK);
        }

        User user = userService.findByWxOpenId(jscode2sessionJson.getString("openid"));
        if(user == null){
//            https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
            String tokenUrl = WeiXinConfig.apiUrl+"/cgi-bin/token?grant_type=client_credential&appid=wxfbcfc5894c14db5d&secret=a301f714391543860b107fe8697d8915";
            String tokenRes = HttpUtil.get(tokenUrl);

            log.error(tokenRes);
            JSONObject tokenJson= JSONObject.parseObject(tokenRes);

//            https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN
            String getuserphonenumberUrl = WeiXinConfig.apiUrl+"/wxa/business/getuserphonenumber?access_token="+tokenJson.getString("access_token");

            Map<String , String> params = new HashMap<>();
            params.put("access_token",tokenJson.getString("access_token"));
            params.put("code",phoneCode);
            JSONObject pjson = new JSONObject();
//            pjson.put("access_token",tokenJson.getString("access_token"));
            pjson.put("code",phoneCode);
            String getuserphonenumberRes = null;
            try {
                getuserphonenumberRes = HttpClientUtils.sendPost(getuserphonenumberUrl, pjson.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }

            log.error(getuserphonenumberRes);
//            {"errcode":0,"errmsg":"ok","phone_info":{"phoneNumber":"13614476684","purePhoneNumber":"13614476684","countryCode":"86","watermark":{"timestamp":1661509301,"appid":"wxfbcfc5894c14db5d"}}}

            JSONObject getuserphonenumberJson= JSONObject.parseObject(getuserphonenumberRes);
            JSONObject phoneInfo = getuserphonenumberJson.getJSONObject("phone_info");
            user = userService.findByPhone(phoneInfo.getString("purePhoneNumber"));
            if(user == null){
                Map<String, Object> userMap = new HashMap<String, Object>(2) {{
                    put("code", "-2");
                    put("msg", "手机号没有对应的账号");
                }};
                // 返回 token 与 用户信息
                Map<String, Object> result = PageUtil.toMpContent(userMap);
                return new ResponseEntity<>(result, HttpStatus.OK);
            }
            user.setWxOpenId(jscode2sessionJson.getString("openid"));
//            try {
//                userService.update(user);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }

        }
        // 生成令牌与第三方系统获取令牌方式
        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
        log.error(userDetails.toString());
        Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        log.error(authentication.toString());
        SecurityContextHolder.getContext().setAuthentication(authentication);


        String token = tokenProvider.createToken(authentication);
        log.error(token);
        final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal();
        Map<String, Object> userMap = new HashMap<String, Object>(2) {{
            put("code", "0");
            put("token", properties.getTokenStartWith() + token);
            put("userinfo", jwtUserDto);
        }};
        // 保存在线信息
        onlineUserService.save(jwtUserDto, token, request);
        // 返回 token 与 用户信息
        Map<String, Object> result = PageUtil.toMpContent(userMap);
        if (loginProperties.isSingleLogin()) {
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(user.getUsername(), token);
        }

        return new ResponseEntity<>(result, HttpStatus.OK);
    }
}
